import libUtils from '@/lib/utils';
import * as ifs from '@/obj/ifs';
import * as tvs from '@/obj/typeValue';
import Vue from 'vue';
import Vuex, { StoreOptions } from 'vuex';
import XEUtils from 'xe-utils';

Vue.use(Vuex);

interface IRootState {
  socket: {
    isConnected: boolean;
    message: string;
    reconnectError: boolean;
  };
  queue: any;
  heartbeat: any;
}
const talkingHandle = (m: ifs.I_receWsMsgParams) => {
  Vue.prototype.$bus.$emit('__TALKING__', m); // 聊天工具
};
const messageHandle = (m: ifs.I_receWsMsgParams) => {
  switch (m.m.t) {
    case tvs.V_msgType.ALARM:
      Vue.prototype.$bus.$emit('__ALARM__', m); // 报警
      break;
    case tvs.V_msgType.BROADCAST:
      Vue.prototype.$bus.$emit('__BROADCAST__', m); // 广播
      break;
    case tvs.V_msgType.EARLY_WARNING:
      Vue.prototype.$bus.$emit('__EARLY_WARNING__', m); // 预警
      break;
    case tvs.V_msgType.NOTICE:
      Vue.prototype.$bus.$emit('__NOTICE__', m); // 通知
      break;
    case tvs.V_msgType.TO_DO_LIST:
      Vue.prototype.$bus.$emit('__TO_DO_LIST__', m); // 待办事项
      break;
    case tvs.V_msgType.REFRESH_TOKEN:
      Vue.prototype.$bus.$emit('__REFRESH_TOKEN__', m); // 到期发牌
      break;
    case tvs.V_msgType.WS_SERVER_INFO:
      Vue.prototype.$bus.$emit('__WS_SERVER_INFO__', m); // ws服务器信息
      break;
    case tvs.V_msgType.SUBSCRIPTION:
      Vue.prototype.$bus.$emit('__WS_SUBSCRIPTION__', m); // 消息订阅
      break;
    default:
      console.error('无法识别的WS类型标识');
  }
};
const communicationHandle = (m: ifs.I_receWsMsgParams) => {
  if (m?.m?.d['content'] && typeof m.m.d['content'] === 'string') {
    const content = JSON.parse(m.m.d['content']);
    if (content?.routeID) {
      Vue.prototype.$bus.$emit(content.routeID, content);
    }
  }
};
const store: StoreOptions<IRootState> = {
  state: {
    socket: {
      isConnected: false,
      message: '',
      reconnectError: false
    },
    queue: {},
    heartbeat: null
  },
  mutations: {
    SOCKET_ONOPEN(state: any, event: any): void {
      console.info('ws open');
      Vue.prototype.$socket = event.currentTarget;
      state.socket.isConnected = true;
      state.heartbeat = setInterval(() => {
        const currentTime: number = XEUtils.timestamp(new Date());
        XEUtils.objectEach(state.queue, (item: any, key: any) => {
          if (item.expire < currentTime) {
            Vue.prototype.$bus.$emit(`ws_${key}`, {
              success: false,
              msg: 'timeout'
            });
            delete state.queue[key];
          }
        });
      }, 1000);
    },
    SOCKET_ONCLOSE(state: any): void {
      state.socket.isConnected = false;
      clearInterval(state.heartbeat);
      XEUtils.clear(state.queue);
    },
    SOCKET_ONERROR(state: any, event: any): void {
      throw new Error(state, event);
    },
    // default handler called for all methods
    SOCKET_ONMESSAGE(state: any, message: any): void {
      state.socket.message = message;
      try {
        if (!message.isTrusted) {
          return;
        }
        const msgIsJson = libUtils.isJSONString(message.data.toString());
        if (msgIsJson) {
          const data = JSON.parse(message.data) as ifs.I_receWsMsgParams;
          switch (data.cmd) {
            case tvs.V_msgCommand.TALKING: // 会话
              talkingHandle(data);
              break;
            case tvs.V_msgCommand.MESSAGE: // 消息
              messageHandle(data);
              break;
            case tvs.V_msgCommand.CUSTOM_COMMUNICATION: // 自定义通讯
              communicationHandle(data);
              break;
            default:
              console.error('无法识别的WS命令');
          }
        } else {
          // 支持心跳检测 ping 返回 ok
          // 获取ws集群hubID getHubID
          // 获取连接的客户端ID  getClientID
          console.info(message.data.toString());
        }
      } catch {
        console.error('SOCKET_MESSAGE_ERROR', message);
      }
    },

    SOCKET_RECONNECT(state: any, count: any): void {
      console.info(state, count);
    },
    SOCKET_RECONNECT_ERROR(state: any): any {
      state.socket.reconnectError = true;
    }
  },
  // actions: {
  //   sendMessage(context: any, obj: any): any {
  //     return new Promise(resolve => {
  //       if (context.state.socket.isConnected) {
  //         const uniqleID: string = XEUtils.uniqueId();
  //         // tslint:disable-next-line:typedef
  //         const params = XEUtils.isObject(obj.outData)
  //           ? JSON.stringify(obj.outData)
  //           : obj.outData;
  //         const outData: any = `*__${obj.outDataType}__\`${uniqleID}\`${params}#`;
  //         Vue.prototype.$socket.send(outData);
  //         context.state.queue[uniqleID] = {
  //           expire:
  //             XEUtils.timestamp(new Date()) + XEUtils.toNumber(obj.timeout)
  //         };
  //         Vue.prototype.$bus.$on(`ws_${uniqleID}`, (val: any) => {
  //           Vue.prototype.$bus.$off(`ws_${uniqleID}`);
  //           resolve(val);
  //         });
  //       } else {
  //         setTimeout(() => {
  //           return context.dispatch('sendMessage', obj);
  //         }, 1000);
  //       }
  //     });
  //   }
  // }
  actions: {
    sendMessage(
      context: any,
      content: ifs.I_sendWsMsgParams
    ): Promise<boolean> {
      return new Promise((resolve, reject) => {
        try {
          if (context.state.socket.isConnected) {
            // Vue.prototype.$socket.send(content);
            Vue.prototype.$socket.send(JSON.stringify(content));
          }
          resolve(true);
        } catch {
          resolve(false);
        }
      });
    }
  }
};
export default new Vuex.Store<IRootState>(store);
